home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / PROGS / DEMOS / BOUNCE / GLUI.C < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  13.2 KB  |  510 lines

  1.  
  2. /*
  3.   glui.c
  4.   Nate Robins, 1997.
  5.  
  6.   OpenGL based user interface.
  7.  
  8.  */
  9.  
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <GL/glut.h>
  13.  
  14. #define GLUI_BORDER  3
  15. #define GLUI_KNOB   40
  16.  
  17. #define GLUI_RAISED  1
  18. #define GLUI_SUNKEN  0
  19.  
  20. #define GLUI_HORIZONTAL 0
  21. #define GLUI_VERTICAL   1
  22.  
  23. #define GLUI_LESS -1
  24. #define GLUI_HIT   0
  25. #define GLUI_MORE  1
  26.  
  27. #define GLUI_HILITE 0.15
  28.  
  29. typedef struct _GLUIslider {
  30.     int type;                /* vertical/horizontal */
  31.     int parent;                /* parent of this slider */
  32.     int window;                /* this sliders window */
  33.     int win_x;                /* slider window x (parent relative) */
  34.     int win_y;                /* slider window y (parent relative) */
  35.     int win_w;                /* slider window width */
  36.     int win_h;                /* slider window height */
  37.     int length;                /* length of the slider in pixels */
  38.     int knob;                /* position of the knob in pixels */
  39.     int lit;                /* currently lit? */
  40.     void (*update)(float);        /* callback for updating (returns %) */
  41.     struct _GLUIslider* next;
  42. } GLUIslider;
  43.  
  44. static GLUIslider* _gluiSliders = NULL;
  45. static GLUIslider* _gluiHit = NULL;
  46.  
  47. static GLUIslider*
  48. _gluiCurrentSlider(void)
  49. {
  50.     GLUIslider* slider = _gluiSliders;
  51.     int window = glutGetWindow();
  52.  
  53.     while(slider) {
  54.     if (slider->window == window)
  55.         break;
  56.     slider = slider->next;
  57.     }
  58.  
  59.     if (!slider)
  60.     printf("glui: _gluiCurrentSlider() failed!\n");
  61.  
  62.     return slider;
  63. }
  64.  
  65. static void
  66. _gluiEmboss(int raised, int lit, int x, int y, int width, int height)
  67. {
  68.     int i;
  69.     float c;
  70.  
  71.     for (i = 0; i < GLUI_BORDER; i++) {
  72.     c = (float)i / (GLUI_BORDER * 5) + (lit ? GLUI_HILITE : 0.0);
  73.     if (raised)
  74.         glColor3f(0.275+c, 0.2+c, 0.2+c);
  75.     else
  76.         glColor3f(0.875-c, 0.8-c, 0.8-c);
  77.     glBegin(GL_LINE_STRIP);
  78.     glVertex2f(x+i+1, y+i);
  79.     glVertex2f(x+width-i-1, y+i);
  80.     glVertex2f(x+width-i-1, y+height-i);
  81.     glEnd();
  82.     }
  83.  
  84.     for (i = 0; i < GLUI_BORDER; i++) {
  85.     c = (float)i / (GLUI_BORDER * 5);
  86.     if (raised)
  87.         glColor3f(0.875-c, 0.8-c, 0.8-c);
  88.     else
  89.         glColor3f(0.275+c, 0.2+c, 0.2+c);
  90.     glBegin(GL_LINE_STRIP);
  91.     glVertex2f(x+i, y+i);
  92.     glVertex2f(x+i, y+height-i-1);
  93.     glVertex2f(x+width-i-1, y+height-i-1);
  94.     glEnd();
  95.     }
  96.  
  97.     c = lit ? GLUI_HILITE : 0.0;
  98.  
  99.     if (raised)
  100.     glColor3f(0.575+c, 0.5+c, 0.5+c);
  101.     else
  102.     glColor3f(0.475+c, 0.3+c, 0.3+c);
  103.     glRectf(x+i, y+i, x+width-i, y+height-i);
  104. }
  105.  
  106. static void
  107. _gluiDisplay(void)
  108. {
  109.     int lit;
  110.     GLUIslider* slider = _gluiCurrentSlider();
  111.  
  112.     lit = slider->lit ? GLUI_HILITE : 0.0;
  113.  
  114.     glClear(GL_COLOR_BUFFER_BIT);
  115.     if (slider->type == GLUI_HORIZONTAL) {
  116.     _gluiEmboss(GLUI_SUNKEN, 0, /* never lit */
  117.             0, 0, slider->length, slider->win_h);
  118.     _gluiEmboss(GLUI_RAISED, slider->lit, 
  119.             slider->knob - GLUI_KNOB/2, GLUI_BORDER,
  120.             GLUI_KNOB + GLUI_BORDER, slider->win_h - GLUI_BORDER*2);
  121.     /* XXX why is it GLUI_KNOB+GLUI_BORDER ? */
  122.     glColor3f(0.975+lit, 0.9+lit, 0.9+lit);
  123.     glBegin(GL_LINES);
  124.     glVertex2f(slider->knob-2, GLUI_BORDER*2-1);
  125.     glVertex2f(slider->knob-2, slider->win_h-GLUI_BORDER*2+1);
  126.     glVertex2f(slider->knob+1, GLUI_BORDER*2-1);
  127.     glVertex2f(slider->knob+1, slider->win_h-GLUI_BORDER*2+1);
  128.     glVertex2f(slider->knob+4, GLUI_BORDER*2-1);
  129.     glVertex2f(slider->knob+4, slider->win_h-GLUI_BORDER*2+1);
  130.     glEnd();
  131.     glColor3f(0.175+lit, 0.1+lit, 0.1+lit);
  132.     glBegin(GL_LINES);
  133.     glVertex2f(slider->knob-3, GLUI_BORDER*2-1);
  134.     glVertex2f(slider->knob-3, slider->win_h-GLUI_BORDER*2+1);
  135.     glVertex2f(slider->knob+0, GLUI_BORDER*2-1);
  136.     glVertex2f(slider->knob+0, slider->win_h-GLUI_BORDER*2+1);
  137.     glVertex2f(slider->knob+3, GLUI_BORDER*2-1);
  138.     glVertex2f(slider->knob+3, slider->win_h-GLUI_BORDER*2+1);
  139.     glEnd();
  140.     } else {
  141.     _gluiEmboss(GLUI_SUNKEN, 0, /* never lit */
  142.             0, 0, slider->win_w, slider->length);
  143.     _gluiEmboss(GLUI_RAISED, slider->lit, 
  144.             GLUI_BORDER, slider->knob - GLUI_KNOB/2,
  145.             slider->win_w - GLUI_BORDER*2, GLUI_KNOB + GLUI_BORDER);
  146.     /* XXX why is it GLUI_KNOB+GLUI_BORDER ? */
  147.     glColor3f(0.175+lit, 0.1+lit, 0.1+lit);
  148.     glBegin(GL_LINES);
  149.     glVertex2f(GLUI_BORDER*2-1, slider->knob-2);
  150.     glVertex2f(slider->win_w-GLUI_BORDER*2+1, slider->knob-2);
  151.     glVertex2f(GLUI_BORDER*2-1, slider->knob+1);
  152.     glVertex2f(slider->win_w-GLUI_BORDER*2+1, slider->knob+1);
  153.     glVertex2f(GLUI_BORDER*2-1, slider->knob+4);
  154.     glVertex2f(slider->win_w-GLUI_BORDER*2+1, slider->knob+4);
  155.     glEnd();
  156.     glColor3f(0.975+lit, 0.9+lit, 0.9+lit);
  157.     glBegin(GL_LINES);
  158.     glVertex2f(GLUI_BORDER*2-1, slider->knob-3);
  159.     glVertex2f(slider->win_w-GLUI_BORDER*2+1, slider->knob-3);
  160.     glVertex2f(GLUI_BORDER*2-1, slider->knob+0);
  161.     glVertex2f(slider->win_w-GLUI_BORDER*2+1, slider->knob+0);
  162.     glVertex2f(GLUI_BORDER*2-1, slider->knob+3);
  163.     glVertex2f(slider->win_w-GLUI_BORDER*2+1, slider->knob+3);
  164.     glEnd();
  165.     }
  166.  
  167.     glutSwapBuffers();
  168. }
  169.  
  170. static int
  171. _gluiHitKnob(GLUIslider* slider, int x, int y)
  172. {
  173.     if (slider->type == GLUI_HORIZONTAL) {
  174.     /* we know that we don't have to test the y coordinate because
  175.        the mouse came down in the window (this means that they can
  176.        hit the borders and still move the knob, but that's okay).
  177.      */
  178.     if (x > slider->knob - GLUI_KNOB/2 && x < slider->knob + GLUI_KNOB/2)
  179.         return GLUI_HIT;
  180.     else if (x < slider->knob)
  181.         return GLUI_LESS;
  182.     else
  183.         return GLUI_MORE;
  184.     } else {
  185.     /* we know that we don't have to test the x coordinate because
  186.        the mouse came down in the window (this means that they can
  187.        hit the borders and still move the knob, but that's okay).
  188.      */
  189.     if (y > slider->knob - GLUI_KNOB/2 && y < slider->knob + GLUI_KNOB/2)
  190.         return GLUI_HIT;
  191.     else if (y < slider->knob)
  192.         return GLUI_LESS;
  193.     else
  194.         return GLUI_MORE;
  195.     }
  196. }
  197.  
  198. static void
  199. _gluiConstrainKnob(GLUIslider* slider)
  200. {
  201.     if (slider->knob > slider->length - GLUI_BORDER*2 - GLUI_KNOB/2)
  202.     slider->knob = slider->length - GLUI_BORDER*2 - GLUI_KNOB/2;
  203.     else if (slider->knob < GLUI_BORDER + GLUI_KNOB/2)
  204.     slider->knob = GLUI_BORDER + GLUI_KNOB/2;
  205. }
  206.  
  207.  
  208. static float
  209. _gluiKnobPercent(GLUIslider* slider)
  210. {
  211.     return (float)(slider->knob - GLUI_KNOB/2 - GLUI_BORDER) /
  212.     (slider->length - GLUI_BORDER*3 - GLUI_KNOB);
  213. }
  214.  
  215. static int
  216. _gluiKnobPosition(GLUIslider* slider, float percent)
  217. {
  218.     return GLUI_BORDER + GLUI_KNOB/2 + percent * 
  219.     (slider->length - GLUI_BORDER*3 - GLUI_KNOB);
  220. }
  221.  
  222. static int _gluiX;
  223. static int _gluiY;
  224. static int _gluiMouseDown;
  225.  
  226. static void
  227. _gluiTimer(int value)
  228. {
  229.     GLUIslider* slider = (GLUIslider*)value;
  230.     float percent;
  231.  
  232.     percent = _gluiKnobPercent(slider); 
  233.  
  234.     if (_gluiMouseDown != 0 && percent > 0.0 && percent < 1.0) {
  235.     if (_gluiMouseDown == GLUI_LESS) {
  236.         slider->knob -= slider->length / 25.0;
  237.         _gluiConstrainKnob(slider);
  238.     } else {
  239.         slider->knob += slider->length / 25.0;
  240.         _gluiConstrainKnob(slider);
  241.     }
  242.     glutSetWindow(slider->window);
  243.      glutPostRedisplay();
  244.     slider->update(_gluiKnobPercent(slider));
  245.     glutTimerFunc(20, _gluiTimer, (int)slider);
  246.     }
  247. }
  248.  
  249. static void
  250. _gluiConvertY(GLUIslider* slider, int* y)
  251. {
  252.     if (slider->win_h < 0) {
  253.     glutSetWindow(slider->parent);
  254.     *y = glutGet(GLUT_WINDOW_HEIGHT) + slider->win_h - slider->win_y - *y;
  255.     glutSetWindow(slider->window);
  256.     } else {
  257.     *y = slider->win_h - *y;
  258.     }
  259. }
  260.  
  261. /* ARGSUSED */
  262. static void
  263. _gluiMouse(int button, int state, int x, int y)
  264. {
  265.     GLUIslider* slider = _gluiCurrentSlider();
  266.     int side;
  267.  
  268.     _gluiConvertY(slider, &y);
  269.  
  270.     _gluiX = x;
  271.     _gluiY = y;
  272.     _gluiHit = NULL;
  273.     _gluiMouseDown = GL_FALSE;
  274.  
  275.     if (state == GLUT_DOWN) {
  276.     side = _gluiHitKnob(slider, x, y);
  277.     if (side == GLUI_HIT) {
  278.         _gluiHit = slider;
  279.     } else if (side == GLUI_LESS) {
  280.         slider->knob -= slider->length / 25.0;
  281.         _gluiConstrainKnob(slider);
  282.     } else {
  283.         slider->knob += slider->length / 25.0;
  284.         _gluiConstrainKnob(slider);
  285.     }
  286.     glutPostRedisplay();
  287.     slider->update(_gluiKnobPercent(slider));
  288.     _gluiMouseDown = side;
  289.     if (side != 0) {
  290.         glutTimerFunc(500, _gluiTimer, (int)slider);
  291.     }
  292.     } else {
  293.     slider->lit = GL_FALSE;
  294.     }
  295. }
  296.  
  297. static void
  298. _gluiMotion(int x, int y)
  299. {
  300.     GLUIslider* slider = _gluiHit;
  301.  
  302.     if (slider) {
  303.     _gluiConvertY(slider, &y);
  304.  
  305.     if (slider->type == GLUI_HORIZONTAL) {
  306.         /* clamp the incoming old position, or else the knob will
  307.                possibly "jump" due to the false delta. */
  308.         if (_gluiX < GLUI_BORDER+1)
  309.         _gluiX = GLUI_BORDER+1;
  310.         if (_gluiX > slider->length - GLUI_BORDER*2)
  311.         _gluiX = slider->length - GLUI_BORDER*2;
  312.         /* we don't want to take any action if the mouse pointer
  313.                has moved passed the extents of the slider. */
  314.         if (x > GLUI_BORDER && x < slider->length - GLUI_BORDER*2) {
  315.         slider->knob -= _gluiX - x;
  316.         _gluiX = x;
  317.         }
  318.     } else {
  319.         /* clamp the incoming old position, or else the knob will
  320.                possibly "jump" due to the false delta. */
  321.         if (_gluiY < GLUI_BORDER+1)
  322.         _gluiY = GLUI_BORDER+1;
  323.         if (_gluiY > slider->length - GLUI_BORDER*2)
  324.         _gluiY = slider->length - GLUI_BORDER*2;
  325.         /* we don't want to take any action if the mouse pointer
  326.                has moved passed the extents of the slider. */
  327.         if (y > GLUI_BORDER && y < slider->length - GLUI_BORDER*2) {
  328.         slider->knob -= _gluiY - y;
  329.         _gluiY = y;
  330.         }
  331.     }
  332.     _gluiConstrainKnob(slider);
  333.  
  334.     /* post a display _before_ updating the user, so that the knob
  335.            won't lag behind. */
  336.     glutPostRedisplay();
  337.  
  338.     /* make sure to set the parent window current, otherwise if
  339.            there is OpenGL state being changed in the update callback,
  340.            it will be done to the sliders context! */
  341.     glutSetWindow(slider->parent);
  342.     slider->update(_gluiKnobPercent(slider));
  343.     }
  344. }
  345.  
  346. static void
  347. _gluiPassive(int x, int y)
  348. {
  349.     GLUIslider* slider = _gluiCurrentSlider();
  350.  
  351.     _gluiConvertY(slider, &y);
  352.  
  353.     if (_gluiHitKnob(slider, x, y) == 0)
  354.     slider->lit = GL_TRUE;
  355.     else
  356.     slider->lit = GL_FALSE;
  357.  
  358.     glutPostRedisplay();
  359. }
  360.  
  361. /* ARGSUSED */
  362. static void
  363. _gluiEntry(int state)
  364. {
  365.     GLUIslider* slider = _gluiCurrentSlider();
  366.  
  367.     /* set the lit flag to false whether we are coming or going
  368.        because if we are doing either, we can't be on top of the knob!  */
  369.     slider->lit = GL_FALSE;
  370.     glutPostRedisplay();
  371. }
  372.  
  373. void
  374. gluiReshape(int width, int height)
  375. {
  376.     float percent;
  377.     int x, y, w, h;
  378.     GLUIslider* slider = _gluiSliders;
  379.  
  380.     while (slider) {
  381.     /* we need to get the width and height of the parent, so set
  382.            it current. */
  383.     glutSetWindow(slider->parent);
  384.  
  385.     /* all this mumbo jumbo takes care of the negative arguments
  386.            to attach the slider to different sides of the window. */
  387.     x = slider->win_x;
  388.     if (x < 0)
  389.         x = width - slider->win_w + x + 1;
  390.     y = slider->win_y;
  391.     if (y < 0)
  392.         y = height - slider->win_h + y + 1;
  393.     w = slider->win_w;
  394.     if (w < 0)
  395.         w = glutGet(GLUT_WINDOW_WIDTH) + slider->win_w - slider->win_x;
  396.     h = slider->win_h;
  397.     if (h < 0)
  398.         h = glutGet(GLUT_WINDOW_HEIGHT) + slider->win_h - slider->win_y;
  399.  
  400.     glutSetWindow(slider->window);
  401.     glutPositionWindow(x, y);
  402.     glutReshapeWindow(w, h);
  403.  
  404.      percent = _gluiKnobPercent(slider);
  405.  
  406.     if (slider->type == GLUI_HORIZONTAL)
  407.         slider->length = w;
  408.     else
  409.         slider->length = h;
  410.  
  411.     slider->knob = _gluiKnobPosition(slider, percent);
  412.  
  413.     _gluiConstrainKnob(slider);
  414.  
  415.     glViewport(0, 0, w, h);
  416.     glMatrixMode(GL_PROJECTION);
  417.     glLoadIdentity();
  418.     gluOrtho2D(0, w, 0, h);
  419.     glMatrixMode(GL_MODELVIEW);
  420.     glLoadIdentity();
  421.     
  422.     slider = slider->next;
  423.     }
  424. }
  425.  
  426.  
  427.  
  428. int
  429. gluiVerticalSlider(int parent, int x, int y, int width, int height,
  430.            float percent, void (*update)(float))
  431. {
  432.     GLUIslider* slider = (GLUIslider*)malloc(sizeof(GLUIslider));
  433.     slider->next = _gluiSliders;
  434.     _gluiSliders = slider;
  435.  
  436.     slider->type = GLUI_VERTICAL;
  437.     slider->parent = parent;
  438.     slider->window = glutCreateSubWindow(parent, x, y, width, height);
  439.     slider->win_x = x;
  440.     slider->win_y = y;
  441.     slider->win_w = width;
  442.     slider->win_h = height;
  443.     slider->update = update;
  444.     slider->lit = GL_FALSE;
  445.  
  446. /*     glutSetCursor(GLUT_CURSOR_LEFT_RIGHT); */
  447.     glutDisplayFunc(_gluiDisplay);
  448.     glutEntryFunc(_gluiEntry);
  449.     glutMouseFunc(_gluiMouse);
  450.     glutMotionFunc(_gluiMotion);
  451.     glutPassiveMotionFunc(_gluiPassive);
  452.  
  453.     glDisable(GL_LIGHTING);
  454.     glDisable(GL_DEPTH_TEST);
  455.  
  456.     slider->length = height;
  457.     if (height < 0) {
  458.     glutSetWindow(parent);
  459.     slider->length = glutGet(GLUT_WINDOW_HEIGHT) + height - slider->win_y;
  460.     }
  461.  
  462.     slider->knob = _gluiKnobPosition(slider, percent);
  463.     _gluiConstrainKnob(slider);
  464.  
  465.     return slider->window;
  466. }
  467.  
  468.  
  469. /* On a horizontal slider, the height must be non-negative. */
  470.  
  471. int
  472. gluiHorizontalSlider(int parent, int x, int y, int width, int height,
  473.              float percent, void (*update)(float))
  474. {
  475.     GLUIslider* slider = (GLUIslider*)malloc(sizeof(GLUIslider));
  476.     slider->next = _gluiSliders;
  477.     _gluiSliders = slider;
  478.  
  479.     slider->type = GLUI_HORIZONTAL;
  480.     slider->parent = parent;
  481.     slider->window = glutCreateSubWindow(parent, x, y, width, height);
  482.     slider->win_x = x;
  483.     slider->win_y = y;
  484.     slider->win_w = width;
  485.     slider->win_h = height;
  486.     slider->update = update;
  487.     slider->lit = GL_FALSE;
  488.  
  489. /*     glutSetCursor(GLUT_CURSOR_LEFT_RIGHT); */
  490.     glutDisplayFunc(_gluiDisplay);
  491.     glutEntryFunc(_gluiEntry);
  492.     glutMouseFunc(_gluiMouse);
  493.     glutMotionFunc(_gluiMotion);
  494.     glutPassiveMotionFunc(_gluiPassive);
  495.  
  496.     glDisable(GL_LIGHTING);
  497.     glDisable(GL_DEPTH_TEST);
  498.  
  499.     slider->length = width;
  500.     if (width < 0) {
  501.     glutSetWindow(parent);
  502.     slider->length = glutGet(GLUT_WINDOW_WIDTH) + width - slider->win_x;
  503.     }
  504.  
  505.     slider->knob = _gluiKnobPosition(slider, percent);
  506.     _gluiConstrainKnob(slider);
  507.  
  508.     return slider->window;
  509. }
  510.